﻿using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.TextManager.Interop;
using System;
using System.ComponentModel.Design;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
using Task = System.Threading.Tasks.Task;

namespace VSIX_Commands_Test
{
    /// <summary>
    /// Command handler
    /// </summary>
    internal sealed class Command1
    {
        /// <summary>
        /// Command ID.
        /// </summary>
        public const int CommandId = 0x0100;

        /// <summary>
        /// Command menu group (command set GUID).
        /// </summary>
        public static readonly Guid CommandSet = new Guid("951e9b05-78e2-44e6-819d-7553e0ac5a6a");

        /// <summary>
        /// VS Package that provides this command, not null.
        /// </summary>
        private readonly AsyncPackage package;

        /// <summary>
        /// Initializes a new instance of the <see cref="Command1"/> class.
        /// Adds our command handlers for menu (commands must exist in the command table file)
        /// </summary>
        /// <param name="package">Owner package, not null.</param>
        /// <param name="commandService">Command service to add command to, not null.</param>
        private Command1(AsyncPackage package, OleMenuCommandService commandService)
        {
            this.package = package ?? throw new ArgumentNullException(nameof(package));
            commandService = commandService ?? throw new ArgumentNullException(nameof(commandService));

            var menuCommandID = new CommandID(CommandSet, CommandId);
            var menuItem = new MenuCommand(this.Execute, menuCommandID);
            commandService.AddCommand(menuItem);
        }

        /// <summary>
        /// Gets the instance of the command.
        /// </summary>
        public static Command1 Instance
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the service provider from the owner package.
        /// </summary>
        private Microsoft.VisualStudio.Shell.IAsyncServiceProvider ServiceProvider
        {
            get
            {
                return this.package;
            }
        }

        /// <summary>
        /// Initializes the singleton instance of the command.
        /// </summary>
        /// <param name="package">Owner package, not null.</param>
        public static async Task InitializeAsync(AsyncPackage package)
        {
            // Switch to the main thread - the call to AddCommand in Command1's constructor requires
            // the UI thread.
            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken);

            OleMenuCommandService commandService = await package.GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService;
            Instance = new Command1(package, commandService);
        }

        /// <summary>
        /// This function is the callback used to execute the command when the menu item is clicked.
        /// See the constructor to see how the menu item is associated with this function using
        /// OleMenuCommandService service and MenuCommand class.
        /// </summary>
        /// <param name="sender">Event sender.</param>
        /// <param name="e">Event args.</param>
        private void Execute(object sender, EventArgs e)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            string message = string.Format(CultureInfo.CurrentCulture, "Inside {0}.MenuItemCallback()", this.GetType().FullName);
            string title = "Command1";

            //// Show a message box to prove we were here
            //VsShellUtilities.ShowMessageBox(
            //    this.package,
            //    message,
            //    title,
            //    OLEMSGICON.OLEMSGICON_INFO,
            //    OLEMSGBUTTON.OLEMSGBUTTON_OK,
            //    OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
            int v = GetCaretInfo();
        }
        /// <summary>
        /// 获取光标信息
        /// </summary>
        /// <returns></returns>
        public int GetCaretInfo()
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            // 1. 获取文本管理器服务
            Task<object> task = ServiceProvider.GetServiceAsync(typeof(SVsTextManager));
            task.Wait();
            var textManager = task.Result as IVsTextManager;
            if (textManager == null)
            {
                return 0;
            }

            // 2. 获取活动文本视图
            textManager.GetActiveView(1, null, out IVsTextView vsTextView);
            if (vsTextView == null)
            {
                return 0;
            }

            // 3. 转换为 WPF 文本视图
            var userData = vsTextView as IVsUserData;
            if (userData == null)
            {
                return 0;
            }

            Guid guidViewHost = Microsoft.VisualStudio.Editor.DefGuidList.guidIWpfTextViewHost;
            if (userData.GetData(ref guidViewHost, out object viewHost) != Microsoft.VisualStudio.VSConstants.S_OK)
            {
                return 0;
            }

            IWpfTextViewHost wpfTextViewHost = viewHost as IWpfTextViewHost;
            IWpfTextView wpfTextView = wpfTextViewHost?.TextView;

            if (wpfTextView == null)
            {
                return 0;
            }

            // 4. 获取光标信息
            // 方法1: 使用 IMultiSelectionBroker (VS2019+)
            try
            {
                // 获取多选择代理
                var broker = wpfTextView.GetMultiSelectionBroker();

                // 使用 SelectedSpans 获取选择区域数量（即光标数量）
                // 注意：每个选择区域对应一个光标
                int count = broker.SelectedSpans.Count;
                return count;
            }
            catch
            {
                // 方法2: 使用 Caret.SecondaryCarets (VS2017+)
                try
                {
                    // SecondaryCarets 只包含副光标
                    int secondaryCount = 0/*wpfTextView.Caret.SecondaryCarets.Count*/;
                    // 总光标数 = 主光标(1) + 副光标数量
                    int totalCarets = 1 + secondaryCount;
                    return secondaryCount;
                }
                catch
                {
                    // 方法3: 使用 Selection.SelectedSpans (回退方案)
                    try
                    {
                        int selectionCount = wpfTextView.Selection.SelectedSpans.Count;
                        return selectionCount;
                    }
                    catch
                    {
                        // 最终回退：单光标
                        return 1;
                    }
                }
            }


            Microsoft.VisualStudio.Text.IMultiSelectionBroker multiSelectionBroker = wpfTextView.GetMultiSelectionBroker();
            int caretCount = wpfTextView.GetMultiSelectionBroker().SelectedSpans.Count;

            return caretCount;
        }
    }
}
